package com.hys.app.service.erp.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hys.app.framework.database.WebPage;
import com.hys.app.framework.exception.ServiceException;
import com.hys.app.framework.util.BeanUtil;
import com.hys.app.framework.util.DateUtil;
import com.hys.app.framework.util.PageConvert;
import com.hys.app.framework.util.StringUtil;
import com.hys.app.mapper.erp.ProcurementContractMapper;
import com.hys.app.model.erp.dos.ProcurementContract;
import com.hys.app.model.erp.dos.ProcurementContractProduct;
import com.hys.app.model.erp.dto.ProcurementContractDTO;
import com.hys.app.model.erp.dto.ProcurementContractQueryParam;
import com.hys.app.model.erp.enums.ContractStatusEnum;
import com.hys.app.model.erp.enums.NoBusinessTypeEnum;
import com.hys.app.model.erp.vo.ContractAllowable;
import com.hys.app.model.erp.vo.ProcurementContractVO;
import com.hys.app.service.erp.NoGenerateManager;
import com.hys.app.service.erp.ProcurementContractManager;
import com.hys.app.service.erp.ProcurementContractProductManager;
import com.hys.app.service.erp.WarehouseEntryManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * 采购合同业务接口实现类
 * @author dmy
 * 2023-12-05
 */
@Service
public class ProcurementContractManagerImpl extends ServiceImpl<ProcurementContractMapper, ProcurementContract> implements ProcurementContractManager {

    @Autowired
    private ProcurementContractProductManager procurementContractProductManager;

    @Autowired
    private NoGenerateManager noGenerateManager;

    @Autowired
    private WarehouseEntryManager warehouseEntryManager;

    /**
     * 查询采购合同分页列表数据
     *
     * @param params 查询参数
     * @return 分页数据
     */
    @Override
    public WebPage list(ProcurementContractQueryParam params) {
        IPage<ProcurementContract> iPage = this.lambdaQuery()
                .eq(ProcurementContract::getDisabled, 0)
                .like(StringUtil.notEmpty(params.getKeyword()), ProcurementContract::getSn, params.getKeyword())
                .like(StringUtil.notEmpty(params.getSn()), ProcurementContract::getSn, params.getSn())
                .like(StringUtil.notEmpty(params.getSupplierName()), ProcurementContract::getSupplierName, params.getSupplierName())
                .eq(StringUtil.notEmpty(params.getContractStatus()), ProcurementContract::getContractStatus, params.getContractStatus())
                .gt(params.getStartTime() != null, ProcurementContract::getSignTime, params.getStartTime())
                .lt(params.getEndTime() != null, ProcurementContract::getSignTime, params.getEndTime())
                .eq(params.getCreatorId() != null, ProcurementContract::getCreatorId, params.getCreatorId())
                .orderByDesc(ProcurementContract::getCreateTime)
                .page(new Page<>(params.getPageNo(), params.getPageSize()));

        for (ProcurementContract record : iPage.getRecords()) {
            ContractAllowable allowable = new ContractAllowable(record);
            record.setAllowable(allowable);
        }
        return PageConvert.convert(iPage);
    }

    /**
     * 新增合同
     *
     * @param procurementContractDTO 合同信息
     */
    @Override
    @Transactional(value = "goodsTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void add(ProcurementContractDTO procurementContractDTO) {
        //合同信息入库
        ProcurementContract procurementContract = new ProcurementContract();
        BeanUtil.copyProperties(procurementContractDTO, procurementContract);
        //生成合同编号
        String sn = noGenerateManager.generate(NoBusinessTypeEnum.ProcurementContract);
        procurementContract.setSn(sn);
        //设置创建时间
        procurementContract.setCreateTime(DateUtil.getDateline());
        //设置合同状态为未执行
        procurementContract.setContractStatus(ContractStatusEnum.NEW.name());
        //设置合同删除状态为未删除
        procurementContract.setDisabled(0);
        this.save(procurementContract);
        //获取主键ID
        Long id = procurementContract.getId();
        //保存合同商品信息
        this.procurementContractProductManager.saveProduct(id, procurementContractDTO.getProductList());
    }

    /**
     * 编辑合同
     *
     * @param id 主键ID
     * @param procurementContractDTO 合同信息
     */
    @Override
    @Transactional(value = "goodsTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void edit(Long id, ProcurementContractDTO procurementContractDTO) {
        //判断合同是否已被入库单占用
        List<Long> ids = new ArrayList<>();
        ids.add(id);
        boolean isUsed = this.warehouseEntryManager.checkContractIsUsed(ids);
        if (isUsed) {
            throw new ServiceException("当前合同已被入库单占用，无法编辑");
        }
        //获取采购合同旧数据
        ProcurementContract contract  = this.getById(id);
        //复制修改后的数据
        BeanUtil.copyProperties(procurementContractDTO, contract);
        //修改采购合同信息
        this.updateById(contract);
        //入库采购计划商品
        this.procurementContractProductManager.saveProduct(id, procurementContractDTO.getProductList());
    }

    /**
     * 删除合同
     * @param ids 采购计划主键ID集合
     */
    @Override
    @Transactional(value = "goodsTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void delete(List<Long> ids) {
        //判断合同是否已被入库单占用
        boolean isUsed = this.warehouseEntryManager.checkContractIsUsed(ids);
        if (isUsed) {
            throw new ServiceException("删除的合同中存在被入库单占用的，无法删除");
        }
        //将合同状态修改为已删除
        this.lambdaUpdate()
                .set(ProcurementContract::getDisabled, 1)
                .in(ProcurementContract::getId, ids)
                .update();
    }

    /**
     * 获取合同详情
     *
     * @param id 合同ID
     * @return
     */
    @Override
    public ProcurementContractVO getDetail(Long id) {
        ProcurementContract contract = this.getById(id);
        ProcurementContractVO contractVO = new ProcurementContractVO();
        BeanUtil.copyProperties(contract, contractVO);

        //获取合同商品信息
        List<ProcurementContractProduct> goodsList = this.procurementContractProductManager.list(id);
        contractVO.setProductList(goodsList);
        return contractVO;
    }

    /**
     * 获取所有合同信息
     *
     * @param status 合同状态
     * @return
     */
    @Override
    public List<ProcurementContract> listAll(String status) {
        return this.lambdaQuery()
                .eq(StringUtil.notEmpty(status), ProcurementContract::getContractStatus, status)
                .eq(ProcurementContract::getDisabled, 0)
                .list();
    }

    /**
     * 执行合同
     *
     * @param ids 采购计划主键ID集合
     */
    @Override
    @Transactional(value = "goodsTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void execute(List<Long> ids) {
        List<ProcurementContract> contracts = this.lambdaQuery()
                .in(ProcurementContract::getId, ids)
                .list();
        if (contracts == null || contracts.size() == 0) {
            throw new ServiceException("要执行的合同不存在");
        }
        //循环验证合同是否可以执行
        for (ProcurementContract contract : contracts) {
            if (!ContractStatusEnum.NEW.name().equals(contract.getContractStatus())) {
                throw new ServiceException("只有状态为未执行的合同才可被执行");
            }
        }
        //更新合同状态为执行中
        this.lambdaUpdate()
                .set(ProcurementContract::getContractStatus, ContractStatusEnum.EXECUTING.name())
                .in(ProcurementContract::getId, ids)
                .update();
    }

    /**
     * 关闭合同
     *
     * @param ids 采购计划主键ID集合
     */
    @Override
    @Transactional(value = "goodsTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void close(List<Long> ids) {
        List<ProcurementContract> contracts = this.lambdaQuery()
                .in(ProcurementContract::getId, ids)
                .list();
        if (contracts == null || contracts.size() == 0) {
            throw new ServiceException("要关闭的合同不存在");
        }
        //循环验证合同是否可以关闭
        for (ProcurementContract contract : contracts) {
            if (!ContractStatusEnum.EXECUTING.name().equals(contract.getContractStatus())) {
                throw new ServiceException("只有状态为执行中的合同才可被关闭");
            }
        }
        //更新合同状态为已关闭
        this.lambdaUpdate()
                .set(ProcurementContract::getContractStatus, ContractStatusEnum.CLOSED.name())
                .in(ProcurementContract::getId, ids)
                .update();
    }
}
